package com.woniuxy.gateway.filter;

import cn.hutool.jwt.JWTException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.woniuxy.cloud.api.dto.LoginDto;
import com.woniuxy.cloud.demo.Result;
import com.woniuxy.gateway.common.Constant;
import com.woniuxy.gateway.common.JWTHelper;
import io.jsonwebtoken.Claims;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;

import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;


public class JwtTokenAuthenticationFilter implements WebFilter {
    private JWTHelper jwtHelper;
    private ObjectMapper objectMapper;
    private StringRedisTemplate srt;
    private String[] excludeAuthPages;

    private AntPathMatcher apm = new AntPathMatcher();

    public JwtTokenAuthenticationFilter(JWTHelper jwtHelper, ObjectMapper objectMapper, StringRedisTemplate srt, String[] excludeAuthPages) {
        this.jwtHelper = jwtHelper;
        this.objectMapper = objectMapper;
        this.srt = srt;
        this.excludeAuthPages = excludeAuthPages;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain webFilterChain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();

        String path = request.getPath().value();


        //过滤请求白名单
        for (String url : excludeAuthPages) {
            if (apm.match(url, path)) {
                return webFilterChain.filter(exchange);
            }
        }

        String token = resolveToken(request);


        if (StringUtils.isEmpty(token)) {
            return getVoidMono(response);
        }


        try {
            //解析jwt，内部自动判断了jwt是否过期
            Claims claims = jwtHelper.parseJWT(token);
//            System.out.println("解析token" + claims);
            //获取到payload中的数据
            Object o = claims.get("user");

            ObjectMapper mapper = new ObjectMapper();
            LoginDto dto = mapper.convertValue(o, LoginDto.class);
            Object val = srt.opsForHash().get("shared:battery:user:login", dto.getUserId().toString());

            if (StringUtils.isEmpty(val)) {
                throw new RuntimeException("令牌无效");
            }
            if (!token.equals(val)) {
                throw new RuntimeException("令牌无效");
            }
            dto.setUserPassword("");

            //放入到header
            request.mutate().header("userId", dto.getUserId().toString());
        } catch (JWTException e) {
            return getVoidMono(response);
        } catch (Exception e) {
            return getVoidMono(response);
        }


        return webFilterChain.filter(exchange);
    }

    /**
     * 根据属性名获取属性值
     *
     * @param fieldName
     * @param o
     * @return
     */
    private static Object getFieldValueByName(String fieldName, Object o) {
        try {
            String firstLetter = fieldName.substring(0, 1).toUpperCase();
            String getter = "get" + firstLetter + fieldName.substring(1);
            Method method = o.getClass().getMethod(getter, new Class[]{});
            Object value = method.invoke(o, new Object[]{});
            return value;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 从请求头中获取token
     *
     * @param request
     */
    private String resolveToken(ServerHttpRequest request) {
        String token = request.getHeaders().getFirst(Constant.TOKEN);
//        System.out.println("查看过没有过这一步" + token);
        if (StringUtils.hasLength(token))
            return token;
        return null;
    }


    private Mono<Void> getVoidMono(ServerHttpResponse response) {
        Result result = Result.newInstance().setCode(403).setMsg("您没有登录，请先登录");

        //解决中文乱码问题
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");

        //转换成json
        String jsonResult = null;
        try {
            jsonResult = objectMapper.writeValueAsString(result);
        } catch (JsonProcessingException e) {
            jsonResult = "error";
        }

        DataBuffer dataBuffer = null;
        try {
            dataBuffer = response.bufferFactory().wrap(jsonResult.getBytes("UTF-8"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return response.writeWith(Mono.just(dataBuffer));
    }
}
